package diplomovka.graphCreator;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.LocalVariable;
import org.jdom.Element;

import diplomovka.graphCreator.modelParts.MAnnotation;
import diplomovka.graphCreator.modelParts.MEnumeration;
import diplomovka.graphCreator.modelParts.MException;
import diplomovka.graphCreator.modelParts.MField;
import diplomovka.graphCreator.modelParts.MInterface;
import diplomovka.graphCreator.modelParts.MMethod;
import diplomovka.graphCreator.modelParts.Type;

public class EnumerationCreator implements ModelPartCreator {

	@Override
	public boolean canHandle(Class loadedClass) {
		return loadedClass.isEnum();
	}

	@Override
	public Type createModelPart(Class loadedClass, JavaClass loadedByteCodes,
			Map<String, Element> configFiles) {
		MEnumeration mEnumeration = new MEnumeration();

		// set type
		Class type = loadedClass.getClass();
		mEnumeration.setType(type);

		// load annotations
		Annotation[] annotations = loadedClass.getDeclaredAnnotations();
		for (Annotation annotation : annotations) {
			MAnnotation mAnnotation = new MAnnotation();
			Class annotationType = annotation.annotationType();
			mAnnotation.setName(annotationType.getName());
			mEnumeration.addAnnotation(mAnnotation);
		}

		// load fields
		Field[] fields = loadedClass.getDeclaredFields();
		for (Field field : fields) {
			if (!field.getName().equals("$VALUES")) {
				MField mField = new MField();
				Annotation[] fieldAnnotations = field.getDeclaredAnnotations();
				for (Annotation fieldAnnotation : fieldAnnotations) {
					MAnnotation annotation = new MAnnotation();
					annotation.setName(fieldAnnotation.annotationType()
							.getName());
					mField.addAnnotation(annotation);
				}

				mField.setType(String.class);

				int fieldModifiers = field.getModifiers();
				mField.setModifiers(fieldModifiers);

				String fieldName = field.getName();
				mField.setName(fieldName);

				mEnumeration.addField(mField);
			}
		}

		// load methods
		Method[] methods = loadedClass.getDeclaredMethods();
		for (Method method : methods) {
			if (!method.getName().equals("valueOf")
					&& !method.getName().equals("values")) {
				List<String> parameterNames = new ArrayList<String>();
				org.apache.bcel.classfile.Method methodByteCode = loadedByteCodes
						.getMethod(method);
				if (methodByteCode.getLocalVariableTable() != null) {
					LocalVariable[] lv = methodByteCode.getLocalVariableTable()
							.getLocalVariableTable();
					for (LocalVariable localVariable : lv) {
						String parameterName = localVariable.getName();
						parameterNames.add(parameterName);
					}
				}

				MMethod mMethod = new MMethod();

				String methodName = method.getName();
				mMethod.setName(methodName);

				Annotation[] methodAnnotations = method
						.getDeclaredAnnotations();
				for (Annotation annotation : methodAnnotations) {
					Class annotationType = annotation.annotationType();
					MAnnotation mAnnotation = new MAnnotation();
					mAnnotation.setName(annotationType.getName());
					mMethod.addAnnotation(mAnnotation);
				}

				Class[] exceptions = method.getExceptionTypes();
				for (Class exception : exceptions) {
					MException mException = new MException();
					mException.setName(exception.getName());
					mMethod.addException(mException);
				}

				int modifiers = method.getModifiers();
				mMethod.setModifiers(modifiers);

				Class[] parameters = method.getParameterTypes();
				int index = 0;
				for (Class parameter : parameters) {
					String parameterName = parameterNames.get(index++);
					mMethod.addParameter(parameterName, parameter);
				}

				Class returnType = method.getReturnType();
				mMethod.setReturnType(returnType);

				mEnumeration.addMethod(mMethod);
			}
		}

		// load enum constants
		Object[] enumConstants = loadedClass.getEnumConstants();
		for (Object constant : enumConstants) {
			mEnumeration.addConstant(constant);
		}

		// load interfaces
		Class[] interfaces = loadedClass.getInterfaces();
		for (Class enumInterface : interfaces) {
			MInterface mInterface = new MInterface();
			mInterface.setName(enumInterface.getName());
			mEnumeration.addInterface(mInterface);
		}

		// set modifiers
		int modifiers = loadedClass.getModifiers();
		mEnumeration.setModifiers(modifiers);

		// set name
		String name = loadedClass.getName();
		mEnumeration.setName(name);

		Package classPackage = loadedClass.getPackage();
		if (classPackage != null) {
			mEnumeration.setPackageName(classPackage.getName());
		}

		return mEnumeration;
	}

}
